package com.jemframework.domain;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;

import com.jemframework.Context;
import com.jemframework.Initializable;
import com.jemframework.domain.identifier.Identifier;

public class DefaultEntityFactory implements EntityFactory, Initializable {

  private Map<Integer, String> mapping = new HashMap<Integer, String>();

  public DefaultEntityFactory() {
    super();
  }

  public void initialize() {

    try {

      Properties properties = new Properties();
      InputStream in = getClass().getClassLoader().getResourceAsStream("entity-factory.properties");
      properties.load(in);

      EntityTypeNameMapping theMapping = Context.getInstance().getEntityTypeNameMapping();

      for (Entry<Object, Object> eachEntry : properties.entrySet()) {
        String key = (String) eachEntry.getKey();
        String value = (String) eachEntry.getValue();
        mapping.put(theMapping.getEntityType(key), value);
      }

    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  @SuppressWarnings("unchecked")
  public <E extends Entity> E create(Identifier anIdentifier) {

    try {

      String theClassName = mapping.get(anIdentifier.getEntityType());
      Class theClass = Class.forName(theClassName);
      Constructor theConstructor = theClass.getConstructor(new Class[] { anIdentifier.getClass() });
      E theInstance = (E) theConstructor.newInstance(new Object[] { anIdentifier });
      return theInstance;

    } catch (ClassNotFoundException e) {
      throw new RuntimeException(e);
    } catch (SecurityException e) {
      throw new RuntimeException(e);
    } catch (NoSuchMethodException e) {
      throw new RuntimeException(e);
    } catch (IllegalArgumentException e) {
      throw new RuntimeException(e);
    } catch (InstantiationException e) {
      throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    } catch (InvocationTargetException e) {
      throw new RuntimeException(e);
    }
  }

  @SuppressWarnings("unchecked")
  public <E extends Entity> E create(int anEntityType) {

    try {

      String theClassName = mapping.get(anEntityType);
      Class theClass = Class.forName(theClassName);
      E theInstance = (E) theClass.newInstance();
      return theInstance;

    } catch (ClassNotFoundException e) {
      throw new RuntimeException(e);
    } catch (InstantiationException e) {
      throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
      throw new RuntimeException(e);
    }
  }
}
